package packets.server;

import java.io.Serializable;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.security.PrivateKey;
import java.security.PublicKey;

import packets.Packet;


import encription.SecurityHandler;
import exceptions.UnverifiedMessageException;

/**
 * a data structure containing a {@link Certificate} for a user , that contains his information
 * and the server's signature , to verify the integrity of the {@link Certificate}
 * used to be send in a {@link Packet} 
 */
public class Certificate implements Serializable{
	/**
	 *
	 */
	private static final long serialVersionUID = 1L;
	private byte[] _data;
	private byte[] _signature;
	/**
	 * Creates an instance of Certificate , fills in the data and signs with the given private key
	 * @param id user's id 
	 * @param publicKey user's public encryption key (although in reality it should be the users digital signature verification key)
	 * @param ip user's latest IP
	 * @param port user's latest port
	 * @param privateKey private key to sign the data with
	 */
	public Certificate(int id, PublicKey publicKey, InetAddress ip , int port , PrivateKey privateKey){
		_signature = null;
		_data = null;
		try {
			_data = SecurityHandler.getBytes(new CertificateData(id , publicKey, ip , port));
			
			_signature = SecurityHandler.sign(_data, privateKey);
		} catch (Exception e) {
			SecurityHandler.catchException("creating certificate", e, false);
			//e.printStackTrace();
		}
	}
	/**
	 * a method to retrieve the certificate data , the data can only be retrieved if the verification key is right
	 * @param verifyKey key to verify the data with
	 * @return the {@link Certificate} data
	 * @throws UnverifiedMessageException if the key doesn't match
	 */
	public CertificateData getData(PublicKey verifyKey) throws UnverifiedMessageException {
		if (SecurityHandler.verify(_data, _signature, verifyKey))
			try {
				return (CertificateData) SecurityHandler.getObject(_data);
			} catch (Exception e) {
				throw new UnverifiedMessageException("certificate could not be verified");
			}
		else throw new UnverifiedMessageException("certificate could not be verified");
	}
	
	/**
	 * updates the IP address and port of the {@link Certificate}
	 * @param inetAddress new IP address and port
	 * @throws Exception if there was an error while updating
	 */
	public void update(InetSocketAddress inetAddress, PrivateKey signKey) throws Exception{
		CertificateData old_c;
		old_c = (CertificateData)SecurityHandler.getObject(_data);
		_data = SecurityHandler.getBytes(new CertificateData(old_c.getId() , old_c.getKey(), inetAddress.getAddress() , inetAddress.getPort()));
		_signature = SecurityHandler.sign(_data, signKey);
	}
	
}
